﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO; // TextReader, TextWriter

namespace simWaifu
{
    //
    // Helper class to allow viewing debug messages
    // without having Visual Studio installed.
    // When initialized it opens (creates if necessary) a
    // text file "debug.txt" in the local app data folder.
    // 
    // Methods:
    // Initialize()                 - open/create text file
    // ShutDown()                   - close text file
    // ConnectToDebugForm()         - enable writing into debug form´s textbox
    // DisconnectFromDebugForm()    - stop writing into debug form (called when it is closed) 
    // Write(string)                - append string to file (no linebreak)
    // WriteLine(string)            - append string and linebreak to file
    //
    // ToDo: rewrite code using delegates and events
    // Well, maybe not. Will make it harder to port to 
    // C++ later, so I might as well skip that step.
    //
    // Todo: close writer after each line to ensure debug log is saved when app crashes
    //

    public static class DebugMessageHandler
    {
        //
        // Data
        //

        // flags for log behaviour:
        // if bShowErrors is true, calls of WriteError() will be logged.
        // if bShowEverything is true, calls of WriteMsg() will be logged, too.
        public static bool bLogErrors = false;
        public static bool bLogMessages = false;
        public static bool bInitialized = false;

        // debug form (useful if writing into debug log file fails 
        // and to watch the output without needing to open the file)
        static FormDebug frmDebug = null;

        // streamreader/writer
        //static TextReader reader = null;
        
        //
        // Public Methods
        //

        public static void WriteError(string s)
        {
            if (bLogErrors)
                Write(s);
        }
        
        public static void WriteErrorLine(string s)
        {
            WriteError(s);
            WriteError(Environment.NewLine);
        }

        public static void WriteMsg(string s)
        {
            if (bLogMessages)
                Write(s);
        }
        
        public static void WriteMsgLine(string s)
        {
            WriteMsg(s);
            WriteMsg(Environment.NewLine);
        }

        public static void Initialize()
        {
            //TextWriter writer = null;

            string debugFileName = GetDebugFileName();
            try
            {
                //writer = new StreamWriter(debugFileName, false);
                WriteLine("simWaifu Debug Output");
                WriteLine(Properties.Settings.Default.AppVersion);
                WriteLine("DebugFileName: " + debugFileName);
            }
            // gotta catch ´em all
            // why can´t I hold all these exceptions?
            // todo: not all of these are necessary anymore (moved writeLine code elsewhere)
            // todo: and some of them can´t even happen to begin with (argument NULL etc)
            // todo: gonna weed them out later
            catch (System.UnauthorizedAccessException)
            {
                DebugMessageHandler.Write("DebugMessageHandler.Initialize(): ");
                DebugMessageHandler.WriteLine("System.UnauthorizedAccessException");
            }
            catch (System.ArgumentNullException)
            {
                DebugMessageHandler.Write("DebugMessageHandler.Initialize(): ");
                DebugMessageHandler.WriteLine("System.ArgumentNullException");
            }
            catch (System.ArgumentException)
            {
                DebugMessageHandler.Write("DebugMessageHandler.Initialize(): ");
                DebugMessageHandler.WriteLine("System.ArgumentException");
            }
            catch (System.IO.FileNotFoundException)
            {
                DebugMessageHandler.Write("DebugMessageHandler.Initialize(): ");
                DebugMessageHandler.WriteLine("System.IO.FileNotFoundException: " + debugFileName);
            }
            catch (System.IO.DirectoryNotFoundException)
            {
                DebugMessageHandler.Write("DebugMessageHandler.Initialize(): ");
                DebugMessageHandler.WriteLine("System.IO.DirectoryNotFoundException: " + debugFileName);
            }
            catch (System.IO.PathTooLongException)
            {
                DebugMessageHandler.Write("DebugMessageHandler.Initialize(): ");
                DebugMessageHandler.WriteLine("System.IO.PathTooLongException" + debugFileName);
            }
            catch (System.Security.SecurityException)
            {
                DebugMessageHandler.Write("DebugMessageHandler.Initialize(): ");
                DebugMessageHandler.WriteLine("System.Security.SecurityException");
            }
            catch (System.IO.IOException)
            {
                DebugMessageHandler.Write("DebugMessageHandler.Initialize(): ");
                DebugMessageHandler.WriteLine("System.IO.IOException");
            }
            catch (System.ObjectDisposedException)
            {
                DebugMessageHandler.Write("DebugMessageHandler.Initialize(): ");
                DebugMessageHandler.WriteLine("System.ObjectDisposedException");
            }
            finally
            {
                // make sure stream is closed
                //if (tr != null)
                //{
                //    tr.Close();
                //}
            }
            bInitialized = true;
        }

        public static void ShutDown()
        {
            /*if (reader != null)
            {
                reader.Close();
                reader = null;
            }*/
            /*
            if (writer != null)
            {
                writer.Close();
                writer = null;
            }*/
            frmDebug = null;
            bInitialized = true;
        }

        public static void ConnectToDebugForm(FormDebug f)
        {
            frmDebug = f;
        }

        public static void DisconnectFromDebugForm()
        {
            frmDebug = null;
        }

        //
        // Private Methods
        //

        public static string GetDebugFileName()
        {
            string appDataPath = Application.LocalUserAppDataPath;
            string debugFileName = Path.Combine(appDataPath, "simWaifuDebug.txt");
            return debugFileName;
        }

        private static void Write(string s)
        {
            // if connected to debug form, pass string
            if ((frmDebug != null) && (!frmDebug.IsDisposed))
            {
                frmDebug.Write(s);
            }
            
            TextWriter writer = null;

            string debugFileName = GetDebugFileName();
            try
            {
                writer = new StreamWriter(debugFileName, true);
                //writer.WriteLine("simWaifu Debug Output");
                //WriteLine(Properties.Settings.Default.AppVersion);
                //WriteLine("DebugFileName: " + debugFileName);
            }
            // gotta catch ´em all
            // why can´t I hold all these exceptions?
            // todo: not all of these are necessary anymore (moved writeLine code elsewhere)
            // todo: and some of them can´t even happen to begin with (argument NULL etc)
            // todo: gonna weed them out later
            catch (System.UnauthorizedAccessException)
            {
                writer.Write("DebugMessageHandler.Write(): ");
                writer.WriteLine("System.UnauthorizedAccessException");
            }
            catch (System.ArgumentNullException)
            {
                writer.Write("DebugMessageHandler.Write(): ");
                writer.WriteLine("System.ArgumentNullException");
            }
            catch (System.ArgumentException)
            {
                writer.Write("DebugMessageHandler.Write(): ");
                writer.WriteLine("System.ArgumentException");
            }
            catch (System.IO.FileNotFoundException)
            {
                writer.Write("DebugMessageHandler.Write(): ");
                writer.WriteLine("System.IO.FileNotFoundException: " + debugFileName);
            }
            catch (System.IO.DirectoryNotFoundException)
            {
                writer.Write("DebugMessageHandler.Write(): ");
                writer.WriteLine("System.IO.DirectoryNotFoundException: " + debugFileName);
            }
            catch (System.IO.PathTooLongException)
            {
                writer.Write("DebugMessageHandler.Write(): ");
                writer.WriteLine("System.IO.PathTooLongException" + debugFileName);
            }
            catch (System.Security.SecurityException)
            {
                writer.Write("DebugMessageHandler.Write(): ");
                writer.WriteLine("System.Security.SecurityException");
            }
            catch (System.IO.IOException)
            {
                writer.Write("DebugMessageHandler.Write(): ");
                writer.WriteLine("System.IO.IOException");
            }
            catch (System.ObjectDisposedException)
            {
                writer.Write("DebugMessageHandler.Write(): ");
                writer.WriteLine("System.ObjectDisposedException");
            }
            finally
            {
                // make sure stream is closed
                //if (tr != null)
                //{
                //    tr.Close();
                //}
            }

            // if file is open, write string
            if (writer != null)
            {
                try
                {
                    //
                    // Mh, flush() doesn´t ensure that data is written.
                    // Data will be only written completely after writer is closed.
                    // Maybe not a good idea to keep it open all the time;
                    // when the app crashes it´s not ensured that all debug info 
                    // was written to the stream.
                    //
                    // ToDo: close writer after a line was written, reopen for next line
                    //
                    writer.Write(s);
                }
                catch (System.IO.IOException)
                {
                    writer.Write("DebugMessageHandler.Write(): ");
                    writer.WriteLine("System.IO.IOException");
                }
                catch (System.ObjectDisposedException)
                {
                    writer.Write("DebugMessageHandler.Write(): ");
                    writer.WriteLine("System.ObjectDisposedException");
                }
                finally
                {
                    writer.Close();
                    // close writer?
                }
            }
            else 
            { 
                // writer is null!
            }
        }

        private static void WriteLine(string s)
        {
            Write(s);
            Write(Environment.NewLine);
        }
    }
}
